package web

import (
	"commerce/cache"
	"commerce/common"
	"commerce/data"
	"commerce/model"
	"commerce/req"
	"commerce/vo"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"
)

/* 此文件是 商品 请求 */

//var searchHotKwPool = sync.Pool{
//	New: func() interface{} {
//		return func(goodsName string) {
//			// 秒精度的时间使用10位足够保存，为了区分相同分数时，再按时间倒序排，这种处理
//			cache.ZIncrBy(common.HOT_KW_LIST, 10000000000+int(time.Now().Unix()), goodsName, common.HOT_KW_LIMIT)
//		}
//	},
//}

//var workPool = sync.Pool{
//	New: func() interface{} {
//		return func(id int, fn func(int)) {
//			fn(id)
//		}
//	},
//}

//func init() {
//searchHotKwPool.Put(searchHotKwPool.New())
//searchHotKwPool.Put(searchHotKwPool.New())
//searchHotKwPool.Put(searchHotKwPool.New())

//workPool.Put(workPool.New())
//workPool.Put(workPool.New())
//workPool.Put(workPool.New())
//workPool.Put(workPool.New())
//}

func GoodsCategory(w http.ResponseWriter, r *http.Request) {

	categoryId, _ := strconv.Atoi(r.PostFormValue("id"))

	category, err := data.GetCategoryById(categoryId)
	if err != nil {
		common.Error.Printf("GoodsCategory err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	categories, err := data.ListSameLevelCategory(category.Parent)
	if err != nil {
		common.Error.Printf("2.GoodsCategory err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	var res vo.GoodsCategoryVo
	var navList []vo.CategoryNav

	for _, c := range categories {
		navList = append(navList, vo.CategoryNav{Id: c.Id, Name: c.Name, FrontName: c.Description})
	}
	res.CurrentCategory = vo.CategoryNav{Id: categoryId, Name: category.Name, FrontName: category.Description}
	res.NavList = navList

	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func GoodsList(w http.ResponseWriter, r *http.Request) {

	brandId, _ := strconv.Atoi(r.PostFormValue("brandId"))
	categoryId, _ := strconv.Atoi(r.PostFormValue("categoryId"))
	page, _ := strconv.Atoi(r.PostFormValue("page"))
	size, _ := strconv.Atoi(r.PostFormValue("size"))
	sort := r.PostFormValue("sort")
	order := r.PostFormValue("order")
	keyword := r.PostFormValue("keyword")

	var pageRes *common.Page
	var categoryList []vo.CategoryNav
	// 按照商品类别 查询
	if categoryId > 0 || brandId > 0 {
		var goodsIdList []int
		var err error
		if categoryId > 0 {
			goodsIdList, err = data.ListGoodsByCategoryId(categoryId, 1)
			if err != nil {
				common.Error.Printf("GoodsList,categoryId:%d err:%v", categoryId, err)
				j, _ := json.Marshal(vo.Err(err.Error()))
				w.Header().Set("Content-Type", "application/json")
				w.WriteHeader(http.StatusOK)
				w.Write(j)
				return
			}
		} else {
			goodsIdList, err = data.ListGoodsIdByBrandId(brandId, 1)
			if err != nil {
				common.Error.Printf("GoodsList,brandId:%d err:%v", brandId, err)
				j, _ := json.Marshal(vo.Err(err.Error()))
				w.Header().Set("Content-Type", "application/json")
				w.WriteHeader(http.StatusOK)
				w.Write(j)
				return
			}
		}
		if goodsIdList == nil || len(goodsIdList) == 0 {
			common.Error.Printf("no GoodsList by categoryId:%d", categoryId)
			j, _ := json.Marshal(vo.Err("没有商品！"))
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write(j)
			return
		}
		pageRes, err = data.PageAppGoods(goodsIdList, page, size)
		if err != nil {
			common.Error.Printf("2.GoodsList by categoryId:%d, err:%v", categoryId, err)
			j, _ := json.Marshal(vo.Err(err.Error()))
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write(j)
			return
		}
	} else {
		// 统计关键词搜索次数
		// 秒精度的时间使用10位足够保存，为了区分相同分数时，再按时间倒序排，这种处理
		cache.ZIncrBy(common.HOT_KW_LIST, 10000000000+int(time.Now().Unix()), keyword, common.HOT_KW_LIMIT)
		//searchHotKwPool.Get().(func(goodsName string))(keyword)

		// 模糊搜索-》提示得到 sku名称 搜索
		var err error
		pageRes, err = data.PageAppGoodsByName(keyword, sort, order, page, size, &categoryList)
		if err != nil {
			common.Error.Printf("3.GoodsList by skuName:%s, err:%v", keyword, err)
			j, _ := json.Marshal(vo.Err(err.Error()))
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write(j)
			return
		}
	}
	var res vo.AppGoodsVo
	res.TotalPages = pageRes.TotalPages
	res.CurrentPage = page
	res.PageSize = size

	if categoryId == 0 {
		res.FilterCategoryList = categoryList
	}

	var skuList []vo.AppSku
	for _, k := range (pageRes.List).([]model.Sku) {
		skuList = append(skuList, vo.AppSku{Id: k.Id, Name: k.Name, MainImg: k.MainImg, RetailPrice: k.RealPrice})
	}
	res.GoodsList = skuList

	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func GoodsCount(w http.ResponseWriter, r *http.Request) {

	j, _ := json.Marshal(vo.Ok(vo.GoodsCountVo{GoodsCount: data.CountGoodsSku(1)}))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func GoodsDetail(w http.ResponseWriter, r *http.Request) {

	skuId, err := strconv.Atoi(r.PostFormValue("id"))
	if err != nil {
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}

	var res vo.GoodsSkuDetailVo

	var group sync.WaitGroup
	// 后续有新功能依次叠加
	group.Add(4)

	// 查询sku 基本信息 & 品牌
	sku, _ := data.GetSkuInfoById(skuId)
	if sku != nil {
		res.Sku = vo.AppSku{Id: sku.Id, Name: sku.Name, MainImg: sku.MainImg, RetailPrice: sku.RealPrice, Desc: sku.Description}
	}
	goods, err := data.GetGoodsById(sku.GoodsId)

	if err == nil {
		go func() {
			// 1
			defer group.Done()

			skuAttrValues, err := data.ListSkuAttrValueBySkuId(skuId, false)
			if err == nil {
				sMap := make(map[string]bool)
				var aList []vo.AttributeVo
				for _, s := range skuAttrValues {
					sMap[fmt.Sprintf("%d_%s", s.AttrId, s.AttrValue)] = true
					aList = append(aList, vo.AttributeVo{Name: s.AttrName, Value: s.AttrValue})
				}
				// 销售规格属性
				res.Attribute = aList

				allSkuAttrValues, err := data.ListGoodsSpec(goods.Id)
				if err == nil {
					var skuIds []int
					var skuId int
					pMap := make(map[int]bool, len(allSkuAttrValues))
					fMap := make(map[int][]model.SkuAttrValue, len(allSkuAttrValues))
					for _, s := range allSkuAttrValues {

						h, _ := fMap[s.AttrId]
						h = append(h, s)
						fMap[s.AttrId] = h

						split := strings.Split(s.SkuIds, ",")
						for _, x := range split {
							skuId, _ = strconv.Atoi(x)
							pMap[skuId] = true
						}
					}
					for k, _ := range pMap {
						skuIds = append(skuIds, k)
					}
					var sList []vo.SpecificationVo
					for attrId, vs := range fMap {
						specVo := vo.SpecificationVo{AttrId: attrId, Name: vs[0].AttrName}
						var valueList []vo.Specification
						for _, v := range vs {
							var checked = false
							id := fmt.Sprintf("%d_%s", attrId, v.AttrValue)
							x, _ := sMap[id]
							checked = x
							valueList = append(valueList, vo.Specification{Id: id, Value: v.AttrValue, AttrId: attrId, Checked: checked, SkuIds: v.SkuIds})
						}
						specVo.ValueList = valueList

						sList = append(sList, specVo)
					}
					res.SpecificationList = sList

					// 查询库存&价格&图片（多规格时切换使用）
					inventoryList, err := data.ListGoodsInventory(skuIds)
					if err == nil {
						var pList []vo.SkuStockVo
						for _, i := range inventoryList {
							pList = append(pList, vo.SkuStockVo{SkuId: i.SkuId, Stock: i.Stock, RealPrice: i.RealPrice, MainImg: i.MainImg})
						}
						res.ProductList = pList
					}
				}
			}
		}()

		go func() {
			// 2
			defer group.Done()

			// 查询品牌
			brand, _ := data.GetBrandById(goods.BrandId)
			if brand != nil {
				res.Brand = vo.BrandVo{Id: brand.Id, Name: brand.Name, ImgUrl: brand.Logo, Description: brand.Description}
			}
		}()
	}
	//workPool.Get().(func(id int, fn func(int)))(skuId, func(skuId int) {
	//
	//})
	// 查询商品详情图片列表
	go func() {
		// 3
		defer group.Done()

		goodsImgs, err := data.ListGoodsImgByGoodsId(goods.Id)
		if err == nil {
			var gList []vo.GoodsImgVo
			for _, gi := range goodsImgs {
				gList = append(gList, vo.GoodsImgVo{Id: gi.Id, ImgUrl: gi.ImgUrl})
			}
			res.GalleryList = gList
		}
		res.UserHasCollect = 0
		tokenHeader := r.Header["Token"]
		if tokenHeader == nil || len(tokenHeader) == 0 {
			return
		}
		appUser, err := parseAppToken(tokenHeader[0])
		if err != nil {
			common.Error.Println("parseAppToken err:", err)
			return
		}
		// 用户登录了
		if appUser != nil {
			count, err := data.CountGoodsCollect(appUser.Mid, skuId)
			if err == nil && count > 0 {
				// 有收藏
				res.UserHasCollect = 1
			}
		}
	}()

	// 评价列表
	go func() {
		// 4
		defer group.Done()

		var count int
		comment, err := data.GetFirstGoodsComment(skuId, &count)
		if err != nil {
			common.Error.Printf("err GetFirstGoodsComment for skuId:%d, err:%v", skuId, err)
		} else {
			res.Comment = vo.CommentVo{Count: count, Data: vo.CommentDetailVo{Avatar: comment.MemberAvatar, Nickname: comment.MemberNickName,
				AddTime: comment.CreatedTimeStr, Content: comment.Content}}
		}
		//cList := []vo.CommentVo{{Count: 2, Data: vo.CommentDetailVo{Avatar: "avatar", Nickname: "ss", AddTime: "2021-11-20", Content: "very goods",
		//	ImgList: []vo.CommentDetailImgVo{{Id: 101, ImgUrl: "jd.com"}}}}}
		//res.CommentList = cList
	}()

	// 问答 暂时先没有此功能
	//go func() {
	//	// 5
	//	defer group.Done()
	//	iList := []vo.IssueVo{{Id: 5, Question: "好用吗？", Answer: "特别好~"}}
	//	res.IssueList = iList
	//}()

	finishChannel := make(chan bool)
	go func() {
		group.Wait()
		finishChannel <- true
	}()

x:
	for {
		select {
		case <-time.After(3 * time.Second):
			j, _ := json.Marshal(vo.Err("响应超时"))
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write(j)
			return
		case <-finishChannel:
			// 成功拿到结果
			break x
		}
	}
	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func RelatedSkus(w http.ResponseWriter, r *http.Request) {

	skuId, err := strconv.Atoi(r.PostFormValue("id"))
	if err != nil {
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	skus, err := data.ListNeighbourSku(skuId)
	if err != nil {
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	var res vo.AppGoodsVo
	var list []vo.AppSku
	for _, k := range skus {
		list = append(list, vo.AppSku{Id: k.Id, Name: k.Name, RetailPrice: k.RealPrice, Desc: k.Description, MainImg: k.MainImg})
	}
	res.GoodsList = list

	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

// 直接购买， 也使用类似购物车缓存起来，但和购物车不是一个东西

func BuyToCart(w http.ResponseWriter, r *http.Request) {

	var cartReq req.AddToCartReq
	err := json.NewDecoder(r.Body).Decode(&cartReq)
	if err != nil {
		common.Error.Printf("BuyToCart err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	member := extractUserFromContext(r)
	if member == nil {
		common.DisplayTokenErr(w, http.StatusUnauthorized)
		return
	}
	_, err = data.BuyToCart(member.Mid, cartReq.SkuId, cartReq.Number)
	if err != nil {
		common.Error.Printf("2.BuyToCart err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	j, _ := json.Marshal(vo.Ok(nil))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func CountGoodsComment(w http.ResponseWriter, r *http.Request) {

	valueId, err := strconv.Atoi(r.PostFormValue("valueId"))
	if err != nil {
		common.Error.Printf("CountGoodsComment err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		w.Write(j)
		return
	}
	typeId, _ := strconv.Atoi(r.PostFormValue("typeId"))

	common.Info.Println("typeId:", typeId)

	var count int
	count, err = data.CountSkuComment(valueId)
	if err != nil {
		common.Error.Printf("2.CountGoodsComment err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	j, _ := json.Marshal(vo.Ok(vo.GoodsCommentCountVo{AllCount: count, HasPicCount: 0}))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func GoodsCommentList(w http.ResponseWriter, r *http.Request) {

	var res vo.GoodsCommentListVo

	showType, _ := strconv.Atoi(r.PostFormValue("showType"))

	page, err := strconv.Atoi(r.PostFormValue("page"))
	if err != nil {
		page = 1
	}
	// 目前没有图片评论功能，所以直接返回空值
	if showType == 1 {
		res.CurrentPage = page
		j, _ := json.Marshal(vo.Ok(res))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	valueId, err := strconv.Atoi(r.PostFormValue("valueId"))
	if err != nil {
		common.Error.Printf("CountGoodsComment err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		w.Write(j)
		return
	}
	typeId, _ := strconv.Atoi(r.PostFormValue("typeId"))
	common.Info.Println("typeId:", typeId)

	size, err := strconv.Atoi(r.PostFormValue("size"))
	if err != nil {
		size = 20
	}
	comments, err := data.ListAppComment(valueId, page, size)
	if err != nil {
		common.Error.Printf("2.CountGoodsComment err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	res.CurrentPage = page
	var list []vo.CommentDetailVo
	for _, c := range comments {
		list = append(list, vo.CommentDetailVo{Id: c.Id, Avatar: c.MemberAvatar, Nickname: c.MemberNickName,
			AddTime: c.CreatedTimeStr, Content: c.Content})
	}
	res.List = list

	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}
